/**
 * Project Name:UnifiedPayServiceImpl.java
 * File Name:UnifiedPayServiceImpl.java
 * Date:2018/7/28 下午2:16
 * Copyright (c) 2018, zhang.xiangyu@foxmail.com All Rights Reserved.
*/
package com.meatball.base.pay.order.service.impl;

import com.alipay.api.internal.util.StringUtils;
import com.meatball.component.properties.QrCodeProperties;
import com.meatball.exception.NoPrecedenceException;
import com.meatball.base.pay.order.dao.PayOrderMapper;
import com.meatball.base.pay.order.model.PayOrder;
import com.meatball.base.pay.order.service.UnifiedPayService;
import com.meatball.base.pay.order.vo.PayOrderParams;
import com.meatball.base.pay.trade.dao.PayTradeMapper;
import com.meatball.base.pay.trade.model.PayTrade;
import com.meatball.base.pay.utils.WxpayTradePrecreate;
import com.meatball.utils.AlipayResRedder;
import com.meatball.utils.DateUtil;
import com.meatball.utils.QRCodeToBase64;
import com.meatball.base.pay.utils.AlipayTradePrecreate;
import com.meatball.vo.ResultMsg;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Title: UnifiedPayServiceImpl.java
 * @Description: todo(统一支付实现)
 * @Author 張翔宇
 * @Date 2018/7/28 下午2:16
 * @Version V1.0
 */
@Slf4j
@Service
public class UnifiedPayServiceImpl implements UnifiedPayService {
    private static final String ALIPAY = "Alipay";
    private static final String MICROMESSENGER = "MicroMessenger";

    @Resource
    private QrCodeProperties qrCodeProperties;
    @Resource
    private AlipayTradePrecreate alipayTradePrecreate;
    @Resource
    private WxpayTradePrecreate wxpayTradePrecreate;
    @Resource
    private PayOrderMapper payOrderMapper;
    @Resource
    private PayTradeMapper payTradeMapper;

    @Override
    public ResultMsg unifiedPay(PayOrderParams params) {
        log.info(SecurityUtils.getSubject().getSession().getHost());
        //  保存訂單信息
        PayOrder order = new PayOrder();
        BeanUtils.copyProperties(params, order);
        order.setOrderStatus(0);
        order.setOrderSource("危品汇");
        order.setCreateTime(new Date());
        Double price = params.getTotalAmount() * 100;
        order.setTotalAmount(price.longValue());
        payOrderMapper.insertSelective(order);
        // 生成base64格式的二维码
        String qr = QRCodeToBase64.qrCodeToBase64(qrCodeProperties.getUrl() + "/api/pay/" + order.getId());
        order.setQrCode(qr);
        return new ResultMsg(200, "预下单成功", order);
    }

    @Override
    public ResultMsg payment(Long id, String ua) throws Exception {
        // 定义返回参数
        Map<String, Object> result = new HashMap<>(6);
        log.info("====== 开始接收二维码扫码支付请求 ======");
        if(StringUtils.isEmpty(ua)) {
            throw new NoPrecedenceException("User-Agent为空！");
        } else {
            // 获取待支付订单
            PayOrder payOrder = payOrderMapper.selectByPrimaryKey(id);

            if (ua.contains(ALIPAY)) {
                log.info("支付宝支付");
                // 支付宝下单操作，生成支付宝调用客户端参数
                String form = alipayTradePrecreate.h5Pay(payOrder);
                result.put("payMethod", "alipay");
                result.put("outTradeNo", payOrder.getOutTradeNo());
                result.put("orderName", payOrder.getOrderName());
                result.put("totalAmount", payOrder.getTotalAmountText());
                result.put("createTime", payOrder.getCreateTimeText());
                result.put("form", form);
            } else if (ua.contains(MICROMESSENGER)) {
                log.info("微信支付");
                // 微信下单操作
                wxpayTradePrecreate.doUnifiedOrder(payOrder);
                result.put("payMethod", "wxpay");
                result.put("outTradeNo", payOrder.getOutTradeNo());
                result.put("orderName", payOrder.getOrderName());
                result.put("totalAmount", payOrder.getTotalAmountText());
                result.put("createTime", payOrder.getCreateTimeText());
                //公众号名称，由商户传入
                result.put("appId", "wx2421b1c4370ec43b");
                //时间戳，自1970年以来的秒数
                result.put("timeStamp", System.currentTimeMillis());
                //随机串
                result.put("nonceStr", "");
            } else {
                throw new NoPrecedenceException("请使用系统指定支付方式支付。");
            }
        }
        return new ResultMsg(200, result);
    }

    @Override
    public ResultMsg alipayCallback(HttpServletRequest request) throws Exception {
        //获取支付宝POST过来反馈信息
        Map<String, String> maps = AlipayResRedder.read(request);
        // 验签结果
        boolean verify  = alipayTradePrecreate.verifySignature(maps);
        if(verify) {
            // 获取订单号
            String outTradeNo = maps.get("out_trade_no");
            // 查询订单信息
            PayOrder payOrder = payOrderMapper.selectByOutTradeNo(outTradeNo);
            // 判断支付金额是否与订单金额相等
            String receiptAmount = maps.get("receipt_amount");
            if(payOrder.getTotalAmountText().toString().equals(receiptAmount)) {
                // 更新订单状态
                payOrder.setOrderStatus(1);

                // 插入交易记录
                payTradeMapper.insertSelective(this.assemblyTrade(maps));
            } else {
                payOrder.setOrderStatus(5);
            }
            payOrderMapper.updateByPrimaryKeySelective(payOrder);
            return new ResultMsg(200, "支付成功。", payOrder);
        }
        throw new NoPrecedenceException("支付失败");
    }

    /**
     * 组装交易数据
     * @param maps 支付宝回调数据
     * @return
     */
    private PayTrade assemblyTrade(Map<String, String> maps) {
        PayTrade payTrade = new PayTrade();
        payTrade.setTradeNo(maps.get("trade_no"));
        payTrade.setOutTradeNo(maps.get("out_trade_no"));
        payTrade.setBuyerId(maps.get("buyer_id"));
        payTrade.setBuyerLogonId(maps.get("buyer_logon_id"));
        // 转化为double类型
        Double totalAmount = Double.valueOf(maps.get("total_amount")) * 100;
        payTrade.setTotalAmount(totalAmount.intValue());
        Double receiptAmount = Double.valueOf(maps.get("receipt_amount")) * 100;
        payTrade.setReceiptAmount(receiptAmount.intValue());
        payTrade.setSubject(maps.get("subject"));
        payTrade.setGmtCreate(DateUtil.parseTime(maps.get("gmt_create")));
        payTrade.setGmtPayment(DateUtil.parseTime(maps.get("gmt_payment")));
        payTrade.setCreateTime(new Date());
        return payTrade;
    }
}
